package fr.afcepf.atod18.fw.parser;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import fr.afcepf.atod18.fw.exception.FwException;

public class ParserXml {

    private static final int ERR_ACTION_XML_FORMAT = -2;
    private static final int ERR_FORM_XML_FORMAT = -3;

    /**
     * Fonction permettant de parser un fichier XML.
     * 
     * @author stagiaire
     * 
     * @param String
     *            nomFic : nom du fichier à parser
     * @param List
     *            <Object> listeTag liste des types de données à retrouver dans
     *            le fichier
     * @return une liste de map on genere une map par type de données en entrée
     */

    public List<Map<String, Object>> parse(final String nomFic,
            List<Object> listeTag) throws ParserConfigurationException,
            SAXException, IOException, FwException {

        List<Map<String, Object>> ListeMaps = new ArrayList<Map<String, Object>>();

        /* 1 */
        System.out.println("chargement du fichier " + nomFic);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        /* 2 */
        Document document = builder.parse(nomFic);
        /* 3 */
        Element racine = document.getDocumentElement();

        if ((listeTag == null) || (listeTag.size() == 0)) {
            return null;
        }
        System.out.println("Nbre de tags à traiter " + listeTag.size());

        for (int i = 0; i < listeTag.size(); i++) {
            // boucle sur la liste des tags à mapper
            Object o = listeTag.get(i);
            Class c = o.getClass();

            System.out.println("creation Map n° " + i);
            Map<String, Object> theMap = new HashMap<String, Object>();

            NodeList eltsTags = racine.getElementsByTagName(c.getSimpleName()
                    .toLowerCase()); // recup ds fic xml des struct du tag
            // System.out.println("Liste eltstags contient : "
            // + eltsTags.getLength() + " " + c.getSimpleName());
            /* 4 */// parcours des actions
            for (int j = 0; j < eltsTags.getLength(); j++) {
                try {
                    Object obj = c.newInstance();
                    Node unTagTrt = eltsTags.item(j);
                    // elements action
                    NodeList elements = unTagTrt.getChildNodes();
                    String cleMap = new String();
                    for (int k = 0; k < elements.getLength(); k++) {
                        Node enfant = elements.item(k);

                        if (unTagTrt.getNodeName().equals("action")) {
                            // Vérification de l'ordre et format des balises
                            // type
                            // <action> dans le fichier de configuration xml
                            if ((k == 1 && !enfant.getNodeName().equals("action-name")) ||
                                (k == 3 && !enfant.getNodeName().equals("url-pattern")) ||
                                (k == 5 && !enfant.getNodeName().equals("form-name"))   ||
                                (k == 7 && !enfant.getNodeName().equals("input-name")))
                                throw new FwException(
                                        "Format ou ordre des balises action non respecté dans le fichier xml",
                                        ERR_ACTION_XML_FORMAT);
                        }
                        
                        if (unTagTrt.getNodeName().equals("form")) {
                            // Vérification de l'ordre et format des balises
                            // type
                            // <action> dans le fichier de configuration xml
                            if ((k == 1 && !enfant.getNodeName().equals("form-class")) ||
                                (k == 3 && !enfant.getNodeName().equals("form-name")))
                                throw new FwException(
                                        "Format ou ordre des balises form non respecté dans le fichier xml",
                                        ERR_FORM_XML_FORMAT);
                        }

                        System.out.println("enfant.getNodeName()="
                                + enfant.getNodeName());
                        Field[] listAtrributs = c.getDeclaredFields();
                        for (int z = 0; z < listAtrributs.length; z++) {

                            if (enfant.getNodeName().equals(
                                    listAtrributs[z].getName()
                                            .replace("_", "-"))) {

                                if (z == 0) {
                                    cleMap = enfant.getTextContent();
                                    System.out.println("cleMap = " + cleMap
                                            + "z = " + z);
                                }

                                String nomChamp = listAtrributs[z].getName();

                                nomChamp = nomChamp.substring(0, 1)
                                        .toUpperCase() + nomChamp.substring(1);
                                try {
                                    Method m = c.getMethod("set" + nomChamp,
                                            listAtrributs[z].getType());
                                    try {
                                        m.invoke(obj, enfant.getTextContent());
                                    } catch (IllegalArgumentException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    } catch (InvocationTargetException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    }
                                } catch (NoSuchMethodException e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                                } catch (SecurityException e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                                } catch (DOMException e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                                }
                                // System.out.println(listAtrributs[z].getName()
                                // + " : " + enfant.getTextContent());
                                break;
                            }
                        }
                    }
                    theMap.put(cleMap, obj);
                    // System.out.println(j + "eme ajout dans la map");

                } catch (InstantiationException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            ListeMaps.add(theMap);
            // System.out.println(i + "eme ajout dans la liste de maps");
        }
        return ListeMaps;
    }
}
